package fr.imag.ufrima.ima.project.core.operations;

import java.awt.image.BufferedImage;

import org.apache.log4j.Logger;

import fr.imag.ufrima.ima.project.core.Image;
import fr.imag.ufrima.ima.project.core.ImageOperation;

public class Fusion extends ImageOperation{	
	
	private TypeFusion typeFusion;
	private boolean repeat;
	private Image otherImage;
	private int d1, d2, d3;
	private int mh, mw;

	public Fusion(Image originalImage) {
		super(originalImage);
	}
		
	public BufferedImage doOperation() {
		BufferedImage fusionImage;
		
		initFusion();
		logger.debug(String.format("Serving fusion for image: %s, type fusion: %s and repeat: %b.", otherImage.getName(), typeFusion, repeat));

		long startTime = System.currentTimeMillis();

		if (!repeat) {
			fusionImage = this.makefusion();
		} else {
			fusionImage = this.makefusionrepeat();
		}

		long elapsedTime = System.currentTimeMillis() - startTime;
		logger.debug(String.format("Finishing fusioning images. Time elapsed: %d ms", elapsedTime));
		
		return fusionImage;
	}

	private void initFusion() {
		// traitement de param
		switch (typeFusion) {
			case MEDIUM:
				d1 = 1;
				d2 = 1;
				d3 = 2;
				break;
			case LOW:
				d1 = 1;
				d2 = 3;
				d3 = 4;
				break;
			case HIGH:
				d1 = 3;
				d2 = 1;
				d3 = 4;
				break;
		}

		mh = Math.max(originalImage.getHeight(), otherImage.getHeight());
		mw = Math.max(originalImage.getWidth(), otherImage.getWidth());
	}

	private BufferedImage makefusion() {
		int val;

		BufferedImage fusionImage = new BufferedImage(mw, mh, BufferedImage.TYPE_INT_RGB);

		for (int j = 0; j < mh; j++) {
			for (int i = 0; i < mw; i++) {
				if (j < originalImage.getHeight() && i < originalImage.getWidth()) // exist
																					// en
																					// tab1
				{
					int pval1, pval2, pval3, pval0; // operation intiale
					pval0 = (originalImage.getTab()[i][j][0]);
					pval1 = (originalImage.getTab()[i][j][1]);
					pval2 = (originalImage.getTab()[i][j][2]);
					pval3 = (originalImage.getTab()[i][j][3]);
					val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
					fusionImage.setRGB(i, j, val);

					if (j < otherImage.getHeight() && i < otherImage.getWidth())// somme
					{
						pval0 = (d1 * (otherImage.getTab()[i][j][0]) + d2 * (originalImage.getTab()[i][j][0])) / d3;
						pval1 = (d1 * (otherImage.getTab()[i][j][1]) + d2 * (originalImage.getTab()[i][j][1])) / d3;
						pval2 = (d1 * (otherImage.getTab()[i][j][2]) + d2 * (originalImage.getTab()[i][j][2])) / d3;
						pval3 = (d1 * (otherImage.getTab()[i][j][3]) + d2 * (originalImage.getTab()[i][j][3])) / d3;

						val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
						fusionImage.setRGB(i, j, val);
					}

				}

				else if (j < otherImage.getHeight() && i < otherImage.getWidth()) // exist
																					// pa
																					// en
																					// tab1
																					// et
																					// existe
																					// en
																					// tab2
				{
					int pval1, pval2, pval3, pval0; // operation intiale
					pval0 = (otherImage.getTab()[i][j][0]);
					pval1 = (otherImage.getTab()[i][j][1]);
					pval2 = (otherImage.getTab()[i][j][2]);
					pval3 = (otherImage.getTab()[i][j][3]);
					val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
					fusionImage.setRGB(i, j, val);
				}
			}
		}

		return fusionImage;
	}

	private BufferedImage makefusionrepeat() {
		int val;
		
		BufferedImage fusionImage = new BufferedImage(mw, mh, BufferedImage.TYPE_INT_RGB);

		for (int j = 0; j < mh; j++) {
			for (int i = 0; i < mw; i++) {
				if (j < originalImage.getHeight() && i < originalImage.getWidth()) // exist en tab1
				{
					int pval1, pval2, pval3, pval0; // operation intiale
					pval0 = (originalImage.getTab()[i][j][0]);
					pval1 = (originalImage.getTab()[i][j][1]);
					pval2 = (originalImage.getTab()[i][j][2]);
					pval3 = (originalImage.getTab()[i][j][3]);
					val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
					fusionImage.setRGB(i, j, val);

					if (j < otherImage.getHeight() && i < otherImage.getWidth())// somme
					{
						pval0 = (d1 * (otherImage.getTab()[i][j][0]) + d2 * (originalImage.getTab()[i][j][0])) / d3;
						pval1 = (d1 * (otherImage.getTab()[i][j][1]) + d2 * (originalImage.getTab()[i][j][1])) / d3;
						pval2 = (d1 * (otherImage.getTab()[i][j][2]) + d2 * (originalImage.getTab()[i][j][2])) / d3;
						pval3 = (d1 * (otherImage.getTab()[i][j][3]) + d2 * (originalImage.getTab()[i][j][3])) / d3;

						val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
						fusionImage.setRGB(i, j, val);
					}
					// bordella
					if (j >= otherImage.getHeight()) // /si jai depasser j de tab2
					{
						pval0 = (d1 * (otherImage.getTab()[i % otherImage.getWidth()][j % otherImage.getHeight()][0]) + d2 * (originalImage.getTab()[i][j][0])) / d3;
						pval1 = (d1 * (otherImage.getTab()[i % otherImage.getWidth()][j % otherImage.getHeight()][1]) + d2 * (originalImage.getTab()[i][j][1])) / d3;
						pval2 = (d1 * (otherImage.getTab()[i % otherImage.getWidth()][j % otherImage.getHeight()][2]) + d2 * (originalImage.getTab()[i][j][2])) / d3;
						pval3 = (d1 * (otherImage.getTab()[i % otherImage.getWidth()][j % otherImage.getHeight()][3]) + d2 * (originalImage.getTab()[i][j][3])) / d3;

						val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
						fusionImage.setRGB(i, j, val);

						// this.rez[i][j]*=this.tab2[i%this.tab2.length][j%this.tab2[i%this.tab2.length].length];
					}

					if ((j < otherImage.getHeight()) && (i >= otherImage.getWidth()))// /si jai depasser i et pas j
					{
						pval0 = (d1 * (otherImage.getTab()[i % otherImage.getWidth()][j % otherImage.getHeight()][0]) + d2 * (originalImage.getTab()[i][j][0])) / d3;
						pval1 = (d1 * (otherImage.getTab()[i % otherImage.getWidth()][j % otherImage.getHeight()][1]) + d2 * (originalImage.getTab()[i][j][1])) / d3;
						pval2 = (d1 * (otherImage.getTab()[i % otherImage.getWidth()][j % otherImage.getHeight()][2]) + d2 * (originalImage.getTab()[i][j][2])) / d3;
						pval3 = (d1 * (otherImage.getTab()[i % otherImage.getWidth()][j % otherImage.getHeight()][3]) + d2 * (originalImage.getTab()[i][j][3])) / d3;

						val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
						fusionImage.setRGB(i, j, val);

						// this.rez[i][j]*=this.tab2[i%this.tab2.length][j%this.tab2[i%this.tab2.length].length];
					}
					// fin bordella
				}

				else if (j < otherImage.getHeight() && i < otherImage.getWidth()) // exist pa en tab1 et existe en tab2
				{
					int pval1, pval2, pval3, pval0; // operation intiale
					pval0 = (otherImage.getTab()[i][j][0]);
					pval1 = (otherImage.getTab()[i][j][1]);
					pval2 = (otherImage.getTab()[i][j][2]);
					pval3 = (otherImage.getTab()[i][j][3]);
					val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
					fusionImage.setRGB(i, j, val);

					// bordella2
					if (j >= originalImage.getHeight()) // /si jai depasser j de tab1
					{
						pval0 = (d1 * (otherImage.getTab()[i][j][0]) + d2 * (originalImage.getTab()[i % originalImage.getWidth()][j % originalImage.getHeight()][0])) / d3;
						pval1 = (d1 * (otherImage.getTab()[i][j][1]) + d2 * (originalImage.getTab()[i % originalImage.getWidth()][j % originalImage.getHeight()][1])) / d3;
						pval2 = (d1 * (otherImage.getTab()[i][j][2]) + d2 * (originalImage.getTab()[i % originalImage.getWidth()][j % originalImage.getHeight()][2])) / d3;
						pval3 = (d1 * (otherImage.getTab()[i][j][3]) + d2 * (originalImage.getTab()[i % originalImage.getWidth()][j % originalImage.getHeight()][3])) / d3;

						val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
						fusionImage.setRGB(i, j, val);

						// this.rez[i][j]*=this.tab2[i%this.tab2.length][j%this.tab2[i%this.tab2.length].length];
					}

					if ((j < originalImage.getHeight()) && (i >= originalImage.getWidth()))// /si jai depasser i et pas j
					{
						pval0 = (d1 * (otherImage.getTab()[i][j][0]) + d2 * (originalImage.getTab()[i % originalImage.getWidth()][j % originalImage.getHeight()][0])) / d3;
						pval1 = (d1 * (otherImage.getTab()[i][j][1]) + d2 * (originalImage.getTab()[i % originalImage.getWidth()][j % originalImage.getHeight()][1])) / d3;
						pval2 = (d1 * (otherImage.getTab()[i][j][2]) + d2 * (originalImage.getTab()[i % originalImage.getWidth()][j % originalImage.getHeight()][2])) / d3;
						pval3 = (d1 * (otherImage.getTab()[i][j][3]) + d2 * (originalImage.getTab()[i % originalImage.getWidth()][j % originalImage.getHeight()][3])) / d3;

						val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
						fusionImage.setRGB(i, j, val);

						// this.rez[i][j]*=this.tab2[i%this.tab2.length][j%this.tab2[i%this.tab2.length].length];
					}
					// fin bordella2

				}
			}
		}

		return fusionImage;
	}

	public void setFusionImage(Image otherImage) {
		this.otherImage = otherImage;
	}

	
	public void setTypeFusion(TypeFusion typeFusion) {
		this.typeFusion = typeFusion;
	}

	public void setRepeat(boolean repeat) {
		this.repeat = repeat;
	}
}
